# -*- coding: utf-8 -*-
#
# fusion.feed.feedgenerator
#
# Copyright 2007 Helsinki Institute for Information Technology
# and the authors.
#
# Authors: Harri Hämäläinen <harri.hamalainen@helsinki.fi>
#

# Permission is hereby granted, free of charge, to any person
# obtaining a copy of this software and associated documentation files
# (the "Software"), to deal in the Software without restriction,
# including without limitation the rights to use, copy, modify, merge,
# publish, distribute, sublicense, and/or sell copies of the Software,
# and to permit persons to whom the Software is furnished to do so,
# subject to the following conditions:
#
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

import xml.etree.ElementTree as ET

# These are known to be Atom specific Elements
atom_elements = ['author', 'category', 'content', 'contributor', 'generator', 'email', 
                'entry', 'icon', 'id', 'link', 'name', 'published', 'rights', 
                'title', 'source', 'subtitle', 'summary', 'updated', 'uri']

# These are known to be common attribute values
attribute_names = ['href', 'length', 'rel', 'type', 'xmlns']

ET._namespace_map['http://www.w3.org/2005/Atom'] = 'atom'
ET._namespace_map['http://purl.org/dc/elements/1.1/'] = 'dc'

__all__ = ['to_xml']

def eval_element_name(element_name):
    """
    >>> eval_element_name('dc$title')
    '{http://purl.org/dc/elements/1.1/}title'

    >>> eval_element_name('atom$link')
    '{http://www.w3.org/2005/Atom}link'

    >>> eval_element_name('title')
    'title'

    >>> eval_element_name('ns$index')
    'ns:index'

    """
    if element_name is None: return
    name_components = element_name.split('$')
    if len(name_components) < 2 or name_components[0] == '':
        if name_components[0] in atom_elements:
            return name_components[0]
        else:
            return '{http://p2p-fusion.org/2007/fusion/}'+name_components[0]

    if name_components[0] == 'dc':
        return '{http://purl.org/dc/elements/1.1/}'+name_components[1]
    elif name_components[0] == 'atom':
        return '{http://www.w3.org/2005/Atom}'+name_components[1]
    else:
        return name_components[0]+":"+name_components[1]

def to_xml(json, parent_element, array_element=None):
    """
    >>> json = {'title': 'Otsake', 'link': [{'href': 'http://hiit.fi',\
'type': 'enclosure'}], 'author': 'Harri'}
    >>> pElem = ET.Element('doctest')
    >>> to_xml(json, pElem)
    >>> ET.tostring(pElem)
    '<doctest><author>Harri</author><link href="http://hiit.fi" type="enclosure" />\
<title>Otsake</title></doctest>'

    >>> json = {}
    >>> pElem = ET.Element('doctest')
    >>> to_xml(json, pElem)
    >>> ET.tostring(pElem)
    '<doctest />'

    >>> json = {'alphabets': [{'a': 'A'}, {'b': 'B'}]}
    >>> pElem = ET.Element('doctest')
    >>> to_xml(json, pElem)
    >>> ET.tostring(pElem)
    '<doctest><alphabets><a>A</a></alphabets><alphabets><b>B</b></alphabets></doctest>'

    >>> json = [{'a': 'A'}, {'b': 'B'}]
    >>> pElem = ET.Element('doctest')
    >>> to_xml(json, pElem)
    >>> ET.tostring(pElem)
    '<doctest />'
    """
    if parent_element is None:
        return

    if isinstance(json, dict):
        for key in json:
            if key in attribute_names:
                parent_element.set(key, json[key])

            elif key == '$t':
                parent_element.text = unicode(json[key])
                
            elif key[:6].lower() == 'xmlns$':
                parent_element.set(key[:5]+':'+key[6:], json[key])
            else:
                if isinstance(json[key], list) or isinstance(json[key], tuple):
                    to_xml(json[key], parent_element, key)

                else:
                    child = ET.SubElement(parent_element, eval_element_name(key))
                    to_xml(json[key], child)

    elif isinstance(json, list) or isinstance(json, tuple):
        for index in json:
            if array_element is not None:
                child = ET.SubElement(parent_element, eval_element_name(array_element))
                to_xml(json[json.index(index)], child)

    else:
        parent_element.text = unicode(json)

if __name__ == "__main__":
    import sys
    from simplejson import loads

    if len(sys.argv) < 2:
        print "\nusage\n" \
        + "\tpython "+sys.argv[0]+" json_file\n" \
        + "\tpython "+sys.argv[0]+" --run-tests\n"
        sys.exit()

    if sys.argv[1] == '--run-tests':
        import doctest
        doctest.testmod()

    else:
        file = file(sys.argv[1], "r")
        json_text = file.read()
        file.close()
        json = loads(json_text)
        root = ET.Element("json2xml-test")
        to_xml(json, root, 'json2xml-test-array')
        print ET.tostring(root)
